/*
 * @Description: 可缩放面积柱状图
 * @Author: YoungWind
 * @Date: 2020-09-24 21:31:31
 * @LastEditTime: 2020-09-25 14:20:12
 * @LastEditors: YoungWind
 * @FilePath: \ccd3\src\ccd3\area\charts\ZoomableAreaChart.js
 */
import BaseChart from '../../BaseChart.js'
export default class ZoomableAreaBarChart extends BaseChart {

  constructor(id, data) {
    super(id, data);

    this.xAxisKey = 'x';
    this.yAxisKey = 'y';
    this.yAxisScaleTitle = 'title';

    this.xAxisScale = null;
    this.xAxisGroup = null;

    this.yAxisScale = null;
    this.yAxisGroup = null;

    this.rectGroup = null;
    this.color = 'red';
  }

  /**
   * @description: 设置x轴数据的字段名
   * @param {x轴的key} 
   * @return {当前对象} 
   */
  setXAxisKey(name) {
    this.xAxisKey = name;
    return this;
  }

  /**
   * @description: 设置y轴数据的字段名
   * @param {y轴的key} 
   * @return {当前对象} 
   */
  setYAxisKey(name) {
    this.yAxisKey = name;
    return this;
  }
  /**
   * @description: 设置y轴标题
   * @param {type} 
   * @return {type} 
   */
  setYAxisTitle(title) {
    this.yAxisTitle = title;
    return this;
  }

  init() {
    this.initSvg();
    this.initMainGroup();
    this.initAxes();
    return this;
  }

  initAxes() {
    this.xAxisGroup = this.svg.append('g')
      .attr('id', `${this.id}xAxis`)
      .attr('transform', `translate(${this.margin.left},${this.margin.top + this.innerHeight})`);

    this.yAxisGroup = this.svg.append('g')
      .attr('id', `${this.id}yAxis`)
      .attr('transform', `translate(${this.margin.left},${this.margin.top})`);
  }

  /**
   * @description: 更新视图
   * @param {type} 
   * @return {type} 
   */
  render(data) {
    if (data) {
      this.data = data;
    }
    this.renderScale();
    this.renderAxes();
    this.renderClipPath();
    this.renderPath();
    this.renderZoom();
    return this;
  }

  renderClipPath() {
    /**
     *  <clipPath> 定义一条剪切路径
     */
    this.clipPath = this.mg.append('clipPath')
      .attr('id', `${this.id}ClipPath`);

    // 内部可见区域为矩形
    this.rect = this.clipPath.append("rect")
      .attr('x', 0)
      .attr('y', 0)
      .attr("width", this.innerWidth)
      .attr("height", this.innerHeight);
  }

  renderPath() {
    this.path = this.mg.append("path")
      .attr("clip-path", `url(#${this.id}ClipPath)`)
      .attr("fill", "steelblue")
      .attr("d", () => this.area(this.data, this.xAxisScale))
  }

  /**
   * @description:更新比例尺 
   * @param {type} 
   * @return {type} 
   */
  renderScale() {
    this.xAxisScale = d3.scaleUtc()
      .domain(d3.extent(this.data, d => new Date(d[this.xAxisKey])))
      .range([0, this.innerWidth])

    this.yAxisScale = d3.scaleLinear()
      .domain([0, d3.max(this.data, d => +d[this.yAxisKey])])
      .nice()
      .range([this.innerHeight, 0]);
  }

  /**
   * @description: 更新坐标轴
   * @param {type} 
   * @return {type} 
   */
  renderAxes(newXAxisScale) {
    if (newXAxisScale) {
      this.xAxis = this.xAxisGroup
        .call(d3.axisBottom(newXAxisScale))
      return;
    }

    this.xAxis = this.xAxisGroup
      .call(d3.axisBottom(this.xAxisScale).ticks(this.innerWidth / 80).tickSizeOuter(0))

    this.yAxis = this.yAxisGroup
      .call(d3.axisLeft(this.yAxisScale).ticks(null, "s"))
      .call(g => g.select(".domain").remove())
      .call(g => {
        g.select(".tick:last-of-type text")
          .clone()
          .attr("x", 3)
          .attr("text-anchor", "start")
          .attr("font-weight", "bold")
          .text(this.yAxisTitle)
      })
  }

  /**
   * @description: 更新缩放
   * @param {type} 
   * @return {type} 
   */
  renderZoom() {
    const zoomed = (event) => {
      const newXAxisScale = event.transform.rescaleX(this.xAxisScale);
      this.path.attr("d", this.area(this.data, newXAxisScale));
      //更新X轴比例尺
      this.renderAxes(newXAxisScale);
    }

    const zoom = d3.zoom()
      .scaleExtent([1, 32])
      .extent([[0, 0], [this.innerWidth, this.innerHeight]])
      .translateExtent([[0, -Infinity], [this.innerWidth, Infinity]])
      .on("zoom", zoomed);

    this.mg.call(zoom)
      .transition()
      .duration(750)
      .call(zoom.scaleTo, 4, [this.xAxisScale(Date.UTC(2001, 8, 1)), 0]);
  }

  /**
   * @description: 调用d3中生成path面积区域算法
   * @param {type} 
   * @return {type} 
   */
  area = (data, xAxisScale) => {
    return d3.area()
      .curve(d3.curveStepAfter)
      .x(d => xAxisScale(new Date(d[this.xAxisKey])))
      .y0(this.yAxisScale(0))
      .y1(d => this.yAxisScale(+d[this.yAxisKey]))(data);
  }
}